package vn.codespot.hms.slidingmenu;

import vn.codespot.VisaVietNamAndroid.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.os.ParcelableCompat;
import android.support.v4.os.ParcelableCompatCreatorCallbacks;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.RelativeLayout;

public class SlidingMenu extends RelativeLayout {

    public static final int TOUCHMODE_MARGIN = 0;
    public static final int TOUCHMODE_FULLSCREEN = 1;

    private CustomViewAbove mViewAbove;
    private CustomViewBehind mViewBehind;

    public SlidingMenu(Context context) {
        this(context, null);
    }

    public SlidingMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        LayoutParams behindParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mViewBehind = new CustomViewBehind(context);
        addView(mViewBehind, behindParams);
        LayoutParams aboveParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mViewAbove = new CustomViewAbove(context);
        addView(mViewAbove, aboveParams);
        // register the CustomViewBehind2 with the CustomViewAbove
        mViewAbove.setCustomViewBehind2(mViewBehind);

        // now style everything!
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
        // set the above and behind views if defined in xml
        int viewAbove = ta.getResourceId(R.styleable.SlidingMenu_viewAbove, -1);
        if (viewAbove != -1) {
            View v = LayoutInflater.from(context).inflate(viewAbove, null);
            setViewAbove(v);
        }
        int viewBehind = ta.getResourceId(R.styleable.SlidingMenu_viewBehind, -1);
        if (viewBehind != -1) {
            View v = LayoutInflater.from(context).inflate(viewBehind, null);
            setViewBehind(v);
        }
        int touchModeAbove = ta.getInt(R.styleable.SlidingMenu_aboveTouchMode, TOUCHMODE_MARGIN);
        setTouchModeAbove(touchModeAbove);
        int touchModeBehind = ta.getInt(R.styleable.SlidingMenu_behindTouchMode, TOUCHMODE_MARGIN);
        setTouchModeBehind(touchModeBehind);
        int offsetBehind = (int) ta.getDimension(R.styleable.SlidingMenu_behindOffset, 0);
        setBehindOffset(offsetBehind);
        float scrollOffsetBehind = ta.getFloat(R.styleable.SlidingMenu_behindScrollScale, 0.25f);
        setBehindScrollScale(scrollOffsetBehind);
        int shadowRes = ta.getResourceId(R.styleable.SlidingMenu_shadowDrawable, -1);
        if (shadowRes != -1) {
            setShadowDrawable(shadowRes);
        }
        int shadowWidth = (int) ta.getDimension(R.styleable.SlidingMenu_shadowWidth, 0);
        setShadowWidth(shadowWidth);
        boolean fadeEnabled = ta.getBoolean(R.styleable.SlidingMenu_behindFadeEnabled, true);
        setFadeEnabled(fadeEnabled);
        float fadeDeg = ta.getFloat(R.styleable.SlidingMenu_behindFadeDegree, 0.5f);
        setFadeDegree(fadeDeg);
        // showAbove();
    }

    public void setViewAbove(int res) {
        setViewAbove(LayoutInflater.from(getContext()).inflate(res, null));
    }

    public void setViewAbove(View v) {
        mViewAbove.setContent(v);
        mViewAbove.invalidate();
        mViewAbove.dataSetChanged();
        showAbove();
    }

    public void setViewBehind(int res) {
        setViewBehind(LayoutInflater.from(getContext()).inflate(res, null));
    }

    public void setViewBehind(View v) {
        mViewBehind.setContent(v);
        mViewBehind.invalidate();
        mViewBehind.dataSetChanged();
    }

    public void setSlidingEnabled(boolean b) {
        mViewAbove.setSlidingEnabled(b);
    }

    public boolean isSlidingEnabled() {
        return mViewAbove.isSlidingEnabled();
    }

    /**
     * 
     * @param b
     *            Whether or not the SlidingMenu is in a static mode (i.e.
     *            nothing is moving and everything is showing)
     */
    public void setStatic(boolean b) {
        if (b) {
            setSlidingEnabled(false);
            mViewAbove.setCustomViewBehind2(null);
            mViewAbove.setCurrentItem(1);
            mViewBehind.setCurrentItem(0);
        } else {
            mViewAbove.setCurrentItem(1);
            mViewBehind.setCurrentItem(1);
            mViewAbove.setCustomViewBehind2(mViewBehind);
            setSlidingEnabled(true);
        }
    }

    /**
     * Shows the behind view
     */
    public void showBehind() {
        mViewAbove.setCurrentItem(0);
    }

    /**
     * Shows the above view
     */
    public void showAbove() {
        mViewAbove.setCurrentItem(1);
    }

    /**
     * 
     * @return Whether or not the behind view is showing
     */
    public boolean isBehindShowing() {
        return mViewAbove.getCurrentItem() == 0;
    }

    /**
     * 
     * @return The margin on the right of the screen that the behind view
     *         scrolls to
     */
    public int getBehindOffset() {
        return ((RelativeLayout.LayoutParams) mViewBehind.getLayoutParams()).rightMargin;
    }

    /**
     * 
     * @param i
     *            The margin on the right of the screen that the behind view
     *            scrolls to
     */
    public void setBehindOffset(int i) {
        RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams) mViewBehind.getLayoutParams());
        int bottom = params.bottomMargin;
        int top = params.topMargin;
        int left = params.leftMargin;
        params.setMargins(left, top, i, bottom);
    }

    /**
     * 
     * @param res
     *            The dimension resource to be set as the behind offset
     */
    public void setBehindOffsetRes(int res) {
        int i = (int) getContext().getResources().getDimension(res);
        setBehindOffset(i);
    }

    /**
     * 
     * @return The scale of the parallax scroll
     */
    public float getBehindScrollScale() {
        return mViewAbove.getScrollScale();
    }

    /**
     * 
     * @param f
     *            The scale of the parallax scroll (i.e. 1.0f scrolls 1 pixel
     *            for every 1 pixel that the above view scrolls and 0.0f scrolls
     *            0 pixels)
     */
    public void setBehindScrollScale(float f) {
        mViewAbove.setScrollScale(f);
    }

    public int getTouchModeAbove() {
        return mViewAbove.getTouchModeAbove();
    }

    public void setTouchModeAbove(int i) {
        if (i != TOUCHMODE_FULLSCREEN && i != TOUCHMODE_MARGIN) {
            throw new IllegalStateException("TouchMode must be set to either" + "TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN.");
        }
        mViewAbove.setTouchModeAbove(i);
    }

    public int getTouchModeBehind() {
        return mViewAbove.getTouchModeBehind();
    }

    public void setTouchModeBehind(int i) {
        if (i != TOUCHMODE_FULLSCREEN && i != TOUCHMODE_MARGIN) {
            throw new IllegalStateException("TouchMode must be set to either" + "TOUCHMODE_FULLSCREEN or TOUCHMODE_MARGIN.");
        }
        mViewAbove.setTouchModeBehind(i);
    }

    public void setShadowDrawable(int resId) {
        mViewAbove.setShadowDrawable(resId);
    }

    public void setShadowWidthRes(int resId) {
        setShadowWidth((int) getResources().getDimension(resId));
    }

    public void setShadowWidth(int pixels) {
        mViewAbove.setShadowWidth(pixels);
    }

    public void setFadeEnabled(boolean b) {
        mViewAbove.setBehindFadeEnabled(b);
    }

    public void setFadeDegree(float f) {
        mViewAbove.setBehindFadeDegree(f);
    }

    public static class SavedState extends BaseSavedState {
        boolean mBehindShowing;

        public SavedState(Parcelable superState) {
            super(superState);
        }

        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeBooleanArray(new boolean[] { mBehindShowing });
        }

        public static final Parcelable.Creator<SavedState> CREATOR = ParcelableCompat
                .newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {

                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                });

        SavedState(Parcel in) {
            super(in);
            boolean[] showing = new boolean[1];
            in.readBooleanArray(showing);
            mBehindShowing = showing[0];
        }
    }

    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.mBehindShowing = isBehindShowing();
        return ss;
    }

    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        if (ss.mBehindShowing) {
            showBehind();
        } else {
            showAbove();
        }
    }

    private static final int LOW_DPI_STATUS_BAR_HEIGHT = 19;

    private static final int MEDIUM_DPI_STATUS_BAR_HEIGHT = 25;

    private static final int HIGH_DPI_STATUS_BAR_HEIGHT = 38;

    @SuppressLint("NewApi")
    @Override
    public void setFitsSystemWindows(boolean b) {
        if (Build.VERSION.SDK_INT >= 14) {
            super.setFitsSystemWindows(b);
        } else {
            int topMargin = 0;
            if (b) {
                topMargin = getStatusBarHeight();
            }
            RelativeLayout.LayoutParams params = ((RelativeLayout.LayoutParams) mViewBehind.getLayoutParams());
            int bottom = params.bottomMargin;
            int left = params.leftMargin;
            int right = params.rightMargin;
            params.setMargins(left, topMargin, right, bottom);
        }
    }

    private int getStatusBarHeight() {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
        int statusBarHeight = 0;
        switch (displayMetrics.densityDpi) {
        case DisplayMetrics.DENSITY_HIGH:
            statusBarHeight = HIGH_DPI_STATUS_BAR_HEIGHT;
            break;
        case DisplayMetrics.DENSITY_MEDIUM:
            statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
            break;
        case DisplayMetrics.DENSITY_LOW:
            statusBarHeight = LOW_DPI_STATUS_BAR_HEIGHT;
            break;
        default:
            statusBarHeight = MEDIUM_DPI_STATUS_BAR_HEIGHT;
        }
        return statusBarHeight;
    }

}